package rpcx

import (
	"context"
	"math/rand"
	"net/url"
	"sync"
)

type pool struct {
	p sync.Pool
}

func (pl *pool) Put(list []int) {
	pl.p.Put(list)
}

func (pl *pool) Get() (list []int) {
	if l := pl.p.Get(); l != nil {
		return l.([]int)[0:0]
	} else {
		return make([]int, 0, 64)
	}
}

var WaitList = new(pool)

type Filter func(ctx context.Context, service, method string, node url.Values) bool

type Customized struct {
	filter  Filter
	servers []url.Values
}

func (c *Customized) UpdateServer(servers map[string]string) {
	list := make([]url.Values, 0, len(servers))
	for k, mate := range servers {
		var node url.Values
		if mate == "" {
			node = make(url.Values)
		} else {
			node, _ = url.ParseQuery(mate)
		}

		node.Add("addr", k)

		list = append(list, node)
	}

	c.servers = list // 这里使用新建slice 避免读写同时进行
}

func (c *Customized) Select(ctx context.Context, servicePath, method string, _ interface{}) string {
	waitlist := WaitList.Get()
	defer WaitList.Put(waitlist)

	selectlist := c.servers
	for i := range selectlist {
		if c.filter == nil {
			waitlist = append(waitlist, i)
		} else if c.filter(ctx, servicePath, method, selectlist[i]) {
			waitlist = append(waitlist, i)
		}
	}

	switch len(waitlist) {
	case 0:
		return "" // 没有符合要求的节点
	case 1:
		return selectlist[waitlist[0]].Get("addr") // 只有一个符合要求的节点
	default:
		return selectlist[waitlist[rand.Intn(len(waitlist))]].Get("addr") // 在符合要求的节点中随机选择一个
	}
}

func (c *Customized) SetFilterFunc(function Filter) { c.filter = function }
